#include <string>
#include <vector>
#include <regex>
#include <sstream>

class MarkdownRenderer {
private:
    std::vector<std::string> lines;
    
    std::string processInlineStyles(const std::string& line) {
        std::string result = line;
        result = std::regex_replace(result, std::regex("\\*\\*(.*?)\\*\\*"), "<strong>$1</strong>");
        result = std::regex_replace(result, std::regex("__(.*?)__"), "<strong>$1</strong>");
        result = std::regex_replace(result, std::regex("\\*(.*?)\\*"), "<em>$1</em>");
        result = std::regex_replace(result, std::regex("_(.*?)_"), "<em>$1</em>");
        result = std::regex_replace(result, std::regex("`(.*?)`"), "<code>$1</code>");
        result = std::regex_replace(result, std::regex("\\[(.*?)\\]\\((.*?)\\)"), "<a href=\"$2\">$1</a>");
        return result;
    }
    
    std::string processHeader(const std::string& line) {
        std::smatch match;
        if (std::regex_match(line, match, std::regex("^(#+)\\s*(.*)$"))) {
            int level = match[1].str().length();
            if (level >= 1 && level <= 6) {
                std::string content = processInlineStyles(match[2].str());
                return "<h" + std::to_string(level) + ">" + content + "</h" + std::to_string(level) + ">";
            }
        }
        return line;
    }
    
    bool processCodeBlock(std::vector<std::string>& htmlLines, size_t& i) {
        if (lines[i].find("```") == 0) {
            std::string language = "";
            if (lines[i].length() > 3) {
                language = lines[i].substr(3);
                size_t firstNonSpace = language.find_first_not_of(" \t");
                size_t lastNonSpace = language.find_last_not_of(" \t");
                if (firstNonSpace != std::string::npos && lastNonSpace != std::string::npos) {
                    language = language.substr(firstNonSpace, lastNonSpace - firstNonSpace + 1);
                }
            }
            
            std::stringstream codeBlock;
            codeBlock << "<div class=\"code-block-container\">\n";
            codeBlock << "  <div class=\"code-block-header\">\n";
            if (!language.empty()) {
                codeBlock << "    <span class=\"code-language\">" << language << "</span>\n";
            }
            codeBlock << "    <button class=\"copy-button\" type=\"button\" aria-label=\"复制代码\">\n";
            codeBlock << "      <span class=\"copy-icon\">📋</span>\n";
            codeBlock << "      <span class=\"copy-text\">复制</span>\n";
            codeBlock << "      <span class=\"copy-success\" hidden>已复制!</span>\n";
            codeBlock << "    </button>\n";
            codeBlock << "  </div>\n";
            codeBlock << "  <div class=\"code-block-wrapper\">\n";
            codeBlock << "    <pre class=\"line-numbers\"><code class=\"language-" << (language.empty() ? "none" : language) << "\">";
            
            i++;
            int lineNumber = 1;
            while (i < lines.size() && lines[i].find("```") != 0) {
                std::string escapedLine = lines[i];
                escapedLine = std::regex_replace(escapedLine, std::regex("&"), "&amp;");
                escapedLine = std::regex_replace(escapedLine, std::regex("<"), "&lt;");
                escapedLine = std::regex_replace(escapedLine, std::regex(">"), "&gt;");
                escapedLine = std::regex_replace(escapedLine, std::regex("\""), "&quot;");
                escapedLine = std::regex_replace(escapedLine, std::regex("'"), "&#39;");
                codeBlock << "<span class=\"code-line\" data-line=\"" << lineNumber << "\">" << escapedLine << "</span>\n";
                lineNumber++;
                i++;
            }
            
            codeBlock << "</code></pre>\n";
            codeBlock << "  </div>\n";
            codeBlock << "</div>";
            htmlLines.push_back(codeBlock.str());
            return true;
        }
        return false;
    }
    
    bool processBlockquote(std::vector<std::string>& htmlLines, size_t& i) {
        if (lines[i][0] == '>') {
            std::stringstream blockquote;
            blockquote << "<blockquote>";
            
            while (i < lines.size() && (lines[i][0] == '>' || lines[i].empty())) {
                if (lines[i][0] == '>') {
                    std::string content = lines[i].substr(1);
                    size_t firstNonSpace = content.find_first_not_of(" \t");
                    if (firstNonSpace != std::string::npos) {
                        content = content.substr(firstNonSpace);
                    }
                    content = processInlineStyles(processHeader(content));
                    blockquote << "<p>" << content << "</p>";
                }
                i++;
            }
            
            blockquote << "</blockquote>";
            htmlLines.push_back(blockquote.str());
            return true;
        }
        return false;
    }
    
    bool processList(std::vector<std::string>& htmlLines, size_t& i) {
        if (lines[i][0] == '-' || lines[i][0] == '*' || 
            (lines[i][0] >= '0' && lines[i][0] <= '9') && lines[i].find('.') != std::string::npos) {
            
            bool isOrdered = (lines[i][0] >= '0' && lines[i][0] <= '9');
            std::stringstream list;
            list << (isOrdered ? "<ol>" : "<ul>");
            
            while (i < lines.size() && 
                   (lines[i][0] == '-' || lines[i][0] == '*' || 
                    (lines[i][0] >= '0' && lines[i][0] <= '9') && lines[i].find('.') != std::string::npos ||
                    (lines[i].empty() && i + 1 < lines.size() && 
                     (lines[i+1][0] == '-' || lines[i+1][0] == '*' || 
                      (lines[i+1][0] >= '0' && lines[i+1][0] <= '9') && lines[i+1].find('.') != std::string::npos)))) {
                
                if (!lines[i].empty()) {
                    std::string content = lines[i];
                    if (isOrdered) {
                        size_t dotPos = content.find('.');
                        if (dotPos != std::string::npos) {
                            content = content.substr(dotPos + 1);
                        }
                    } else {
                        content = content.substr(1);
                    }
                    
                    size_t firstNonSpace = content.find_first_not_of(" \t");
                    if (firstNonSpace != std::string::npos) {
                        content = content.substr(firstNonSpace);
                    }
                    
                    content = processInlineStyles(content);
                    list << "<li>" << content << "</li>";
                }
                i++;
            }
            
            list << (isOrdered ? "</ol>" : "</ul>");
            htmlLines.push_back(list.str());
            return true;
        }
        return false;
    }

public:
    std::string render(const std::string& markdown) {
        lines.clear();
        std::istringstream iss(markdown);
        std::string line;
        
        while (std::getline(iss, line)) {
            lines.push_back(line);
        }
        
        std::vector<std::string> htmlLines;
        size_t i = 0;
        
        while (i < lines.size()) {
            if (lines[i].empty()) {
                i++;
                continue;
            }
            
            if (processCodeBlock(htmlLines, i)) {
                i++;
                continue;
            }
            
            if (processBlockquote(htmlLines, i)) {
                continue;
            }
            
            if (processList(htmlLines, i)) {
                continue;
            }
            
            std::string processedLine = processHeader(lines[i]);
            if (processedLine != lines[i]) {
                htmlLines.push_back(processedLine);
            } else {
                processedLine = processInlineStyles(processedLine);
                htmlLines.push_back("<p>" + processedLine + "</p>");
            }
            
            i++;
        }
        
        std::stringstream html;
        for (const auto& htmlLine : htmlLines) {
            html << htmlLine << "\n";
        }
        
        return html.str();
    }
};

std::string markdownToHtml(const std::string& markdown) {
    MarkdownRenderer renderer;
    return renderer.render(markdown);
}